﻿using System;
using System.Data;
using System.Data.SQLite;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Threading;
using DataVirtualization;
namespace JBrute
{
   /// <summary>
   /// Demo implementation of IItemsProvider returning dummy ResultsItem items after
   /// a pause to simulate network/disk latency.
   /// </summary>
   public class ResultsItemProvider : IItemsProvider<ResultsItem>
   {
      private long m_TotalEdictRows;
      private long m_TotalExampleRows;
      private String m_sqlEDict;
      private String m_sqlExample;
      private System.Collections.ArrayList m_entryID;
      public static String connString = "(connect string is initialized as part of ViewModel ctor b/c it depends on location of binary)";
      public bool IsNoLongerNeeded;

      public ResultsItemProvider(String qterm, String sqlEDict, String sqlExample)
      {
         SQLiteConnection conn = new SQLiteConnection(connString);
         m_TotalEdictRows = m_TotalExampleRows = -1;
         m_sqlEDict = sqlEDict;
         m_sqlExample = sqlExample;
         m_entryID = new System.Collections.ArrayList();
         IsNoLongerNeeded = false;
      }

      public ResultsItemProvider(ref System.Collections.ArrayList ids)
      {  // used for VocabList
         SQLiteConnection conn = new SQLiteConnection(connString);
         m_TotalEdictRows = ids.Count;
         m_TotalExampleRows = 0;
         m_sqlEDict = null;
         m_sqlExample = null;
         IsNoLongerNeeded = false; 
         m_entryID = ids;
      }

      public int FetchCount()
      {
         ViewModel.Instance.DebugString= String.Format("FetchCount");
         if (m_TotalEdictRows == -1 && m_TotalExampleRows == -1)
         {
            DateTime start = DateTime.Now;

            Trace.WriteLine("FetchCount...");
            SQLiteConnection conn = new SQLiteConnection(connString);
            m_TotalEdictRows = m_TotalExampleRows = 0;
            if (!String.IsNullOrEmpty(m_sqlEDict))
            {
               SQLiteCommand sqCommand = new SQLiteCommand(m_sqlEDict, conn);
               conn.Open();
               ViewModel.Instance.DebugString = String.Format("FetchCount ... calling ExecuteReader for entries");
               SQLiteDataReader sqReader = sqCommand.ExecuteReader();
               ViewModel.Instance.DebugString = String.Format("FetchCount ... done with ExecuteReader for entries");
               int count = 0;
               while (sqReader.Read())
               {
                  if (IsNoLongerNeeded)
                     return -1;
                  long id = sqReader.GetInt64(0);
                  m_entryID.Add(id);
                  ViewModel.Instance.DebugString = String.Format("FetchCount ... Reading (entries - {0})", count);
                  if (++count > 999)
                     break;
               }
               ViewModel.Instance.DebugString = String.Format("FetchCount ... Reading (entries - done)");
               m_TotalEdictRows = m_entryID.Count;
               ViewModel.Instance.NumResultsEntries = String.Format ("{0} entries", m_TotalEdictRows);
               conn.Close();
            }
            //if (false)
            if (!String.IsNullOrEmpty(m_sqlExample))
            {
               SQLiteCommand sqCommand = new SQLiteCommand(m_sqlExample, conn);
               conn.Open();
               ViewModel.Instance.DebugString = String.Format("FetchCount ... ExecuteReader (examples ....)");
               SQLiteDataReader sqReader = sqCommand.ExecuteReader();
               ViewModel.Instance.DebugString = String.Format("FetchCount ... ExecuteReader (examples .... done)");
               int count = 0;
               while (sqReader.Read())
               {
                  if (IsNoLongerNeeded)
                     return -1;
                  long id = sqReader.GetInt64(0);
                  ViewModel.Instance.DebugString = String.Format("FetchCount ... Reading Examples.... {0}", count);
                  m_entryID.Add(id);
                  if (++count > 999)
                     break;
               }
               ViewModel.Instance.DebugString = String.Format("FetchCount ... Reading Examples.... done");
               m_TotalExampleRows = m_entryID.Count - m_TotalEdictRows;
               ViewModel.Instance.NumResultsExamples = String.Format("{0} examples", m_TotalExampleRows);
               conn.Close();
            }
            Trace.WriteLine("...FetchCount");
            TimeSpan delta = DateTime.Now - start;
            ViewModel.Instance.SearchTime = String.Format("{0} msec", delta.Milliseconds);

         }
         ViewModel.Instance.DebugString = String.Empty;
         return (int)(m_TotalEdictRows + m_TotalExampleRows);
      }

      /// <summary>
      /// Fetches a range of items.
      /// </summary>
      /// <param name="startIndex">The start index.</param>
      /// <param name="count">The number of items to fetch.</param>
      /// <returns></returns>
      public IList<ResultsItem> FetchRange(int startIndex, int count, out int overallCount)
      {
         ViewModel.Instance.DebugString = String.Format("FetchRange:  {0}, {1} (EDict)", startIndex, count);
         Trace.WriteLine("  FetchRange ...");
         overallCount = FetchCount();
         int iCountEdict = 0;
         if (startIndex < m_TotalEdictRows)
            iCountEdict = (startIndex + count  < m_TotalEdictRows) ? count : (int)m_TotalEdictRows - startIndex;

         int iCountExamples = 0;
         if (iCountEdict < count)
            iCountExamples = count - iCountEdict;

         List<ResultsItem> list = new List<ResultsItem>();
         if (list == null)
            throw new InvalidOperationException("WTF?!!  list is null after allocation in ResultsItemProvider::FetchRange");
         if (iCountEdict > 0)
         {
            lock (this)
            {
               SQLiteConnection conn = new SQLiteConnection(connString);
               conn.Open();
               for (int i = startIndex; i < startIndex + iCountEdict && startIndex < m_TotalEdictRows; i++)
               {
                  ResultsItem resultsitem = new ResultsItem();
                  resultsitem.id = (long)m_entryID[i];
                  String sql = "Select r_ele.value from r_ele where r_ele.fk = " + m_entryID[i] + ";";
                  SQLiteCommand sqCommand = new SQLiteCommand(sql, conn);
                  SQLiteDataReader sqReader = sqCommand.ExecuteReader();
                  while (sqReader.Read())
                  {
                     if (IsNoLongerNeeded) 
                        return null;
                     String s = sqReader.GetString(sqReader.GetOrdinal("value"));
                     resultsitem.kana.Add(s);
                  }
                  sql = "Select k_ele.value from k_ele where k_ele.fk = " + m_entryID[i] + ";";
                  sqCommand = new SQLiteCommand(sql, conn);
                  sqReader = sqCommand.ExecuteReader();
                  while (sqReader.Read())
                  {
                     if (IsNoLongerNeeded) 
                        return null;
                     String s = sqReader.GetString(sqReader.GetOrdinal("value"));
                     resultsitem.kanji.Add(s);
                  }
                  sql = "Select gloss.value from sense inner join gloss on sense.id = gloss.fk where (sense.fk =" + m_entryID[i] + ");";
                  sqCommand = new SQLiteCommand(sql, conn);
                  sqReader = sqCommand.ExecuteReader();
                  while (sqReader.Read())
                  {
                     if (IsNoLongerNeeded) 
                        return null;
                     String s = sqReader.GetString(0);
                     resultsitem.gloss.Add(s);
                  }
                  if (resultsitem.kana == null && resultsitem.kanji == null)
                     throw new InvalidOperationException("Results item from dictionary with both Kana and Kanji are NULL");
                  list.Add(resultsitem);
               }
               startIndex += iCountEdict;
               conn.Close();

            }
         }
         // Populate Examples.  sentences.id is in the m_entryID array.
         ViewModel.Instance.DebugString = String.Format("FetchRange:  {0}, {1} (examples)", startIndex, count);
         if (iCountExamples > 0)
         {
            lock (this)
            {
               SQLiteConnection conn = new SQLiteConnection(connString);
               conn.Open();
               for (int i = startIndex; i < startIndex + iCountExamples; i++)
               {
                  ResultsItem resultsitem = new ResultsItem();
                  resultsitem.id = (long)m_entryID[i];
                  String sql = "Select english, japanese from examples where examples.id = " + m_entryID[i] + ";"; 
                  SQLiteCommand sqCommand = new SQLiteCommand(sql, conn);
                  SQLiteDataReader sqReader = sqCommand.ExecuteReader();
                  while (sqReader.Read())
                  {
                     if (IsNoLongerNeeded)
                        return null;
                     String s = sqReader.GetString(sqReader.GetOrdinal("english"));
                     s = s.TrimEnd('\n');
                     resultsitem.gloss.Add(s);
                     s = sqReader.GetString(sqReader.GetOrdinal("japanese"));
                     s = s.TrimEnd('\n');
                     resultsitem.kanji.Add(s);
                  }
                  //sql = "SELECT value from examples_breakout where examples_breakout.id = " + m_entryID[i] + ";";
                  //sqCommand = new SQLiteCommand(sql, conn);
                  //sqReader = sqCommand.ExecuteReader();
                  //while (sqReader.Read())
                  //{
                  //   String s = sqReader.GetString(sqReader.GetOrdinal("value"));
                  //   s = s.TrimEnd('\n');
                  //   resultsitem.kana.Add(s);
                  //}
                  list.Add(resultsitem);
               }
               conn.Close();

            }
         }
         Trace.WriteLine("  ...FetchRange");
         ViewModel.Instance.DebugString = String.Format(String.Empty);
         if (list == null)
            throw new InvalidOperationException("WTF?!!  list is null returning from ResultsItemProvider::FetchRange");
         return list;
      }

      /// <summary>
      /// Pretend to insert an item.
      /// </summary>
      public void InsertItem()
      {
         throw new NotImplementedException();
         //_count++;
      }

      /// <summary>
      /// Pretend to remove an item.
      /// </summary>
      public void RemoveItem()
      {
         throw new NotImplementedException();
         //_count--;
      }
   }
}
